发布于 

Frida 开发和调试环境搭建

前言

Frida 是一款开源的跨平台动态插桩工具,它可以在应用程序运行时注入自定义的 JavaScript 脚本,实现对函数调用的 Hook、参数修改、返回值篡改等操作。与 Xposed 不同,Frida 无需重启设备、无需安装框架,即插即用,且同时支持 Android、iOS、Windows、macOS 和 Linux 等多个平台。

在 Android 逆向工程中,Frida 已经成为最核心的动态分析工具之一。但要让 Frida 正常工作,首先需要搭建一个完整且版本匹配的开发和调试环境。本文将从零开始,带你完成 Frida 全套环境的搭建,并排除常见的坑。

1. Frida 环境准备

1.1 Python 环境安装

Frida 的命令行工具 frida-tools 基于 Python 开发,因此首先需要安装 Python 3.x 环境。

# 推荐使用 Python 3.8 ~ 3.12,避免使用最新版以兼容性问题
# 下载地址: https://www.python.org/downloads/
# Windows 安装时务必勾选 "Add Python to PATH"

安装完成后验证:

python --version
pip --version

提示:如果你使用 Python 3.10+,pip 可能需要显式调用为 pip3

1.2 安装 frida-tools

frida-tools 是 Frida 的官方命令行工具包,包含 fridafrida-psfrida-trace 等常用命令:

pip install frida-tools

这会自动安装 frida-tools 及其依赖 frida(Python 绑定)。安装完成后验证:

frida --version
frida-ps --version

1.3 下载 frida-server

frida-server 是运行在 Android 设备端的守护进程,负责与 PC 端的 frida-tools 通信。它本质上是一个编译好的 ARM 原生可执行文件。

下载地址:https://github.com/frida/frida/releases

选择与 PC 端 frida-tools 版本号完全一致 的 release 包,根据设备 CPU 架构下载对应的文件:

设备架构 下载文件 适用设备
arm64 frida-server-{version}-android-arm64.xz 大多数现代 Android 手机(模拟器一般选 x86)
arm frida-server-{version}-android-arm.xz 32 位 ARM 设备
x86 frida-server-{version}-android-x86.xz x86 模拟器
x86_64 frida-server-{version}-android-x86_64.xz x86_64 模拟器

查看设备架构:

adb shell getprop ro.product.cpu.abi

2. frida-server 部署到 Android 设备

2.1 推送 frida-server 到设备

# 解压下载的 .xz 文件后,将 frida-server 推送到设备
adb push frida-server /data/local/tmp/

# 进入 adb shell
adb shell

# 进入 frida-server 所在目录
cd /data/local/tmp/

# 赋予执行权限
chmod 755 frida-server

2.2 启动 frida-server

frida-server 必须以 root 权限 运行,因为 Frida 需要使用 ptrace 系统调用来注入目标进程:

# 方法一:前台运行(适合调试,Ctrl+C 可停止)
su -c /data/local/tmp/frida-server

# 方法二:后台运行(适合长期使用)
su -c /data/local/tmp/frida-server -D

注意:某些设备的 su 命令可能不支持 -c 参数,此时可以进入 root shell 后直接运行:

su
/data/local/tmp/frida-server -D

2.3 验证连接

在 PC 端执行:

frida-ps -U

如果能列出 Android 设备上的进程列表,说明 frida-server 已正常工作。

3. USB 连接和无线连接

3.1 USB 连接

USB 是最常用的连接方式,稳定且延迟低:

# 1. 确认设备已通过 USB 连接并开启 USB 调试
adb devices

# 2. 启动 frida-server(见上文 2.2 节)

# 3. PC 端通过 -U 参数连接 USB 设备
frida-ps -U
frida -U -f com.example.app -l script.js

3.2 无线连接

无线连接适合不方便使用 USB 线的场景(如设备固定在支架上):

# 1. 先通过 USB 连接设备,获取设备 IP
adb shell ip addr show wlan0
# 或
adb shell ifconfig wlan0

# 2. 开启 TCP/IP 转发(需先 USB 连接)
adb tcpip 5555

# 3. 拔掉 USB 线,通过 IP 连接
adb connect 192.168.1.100:5555

# 4. 确认设备已连接
adb devices

# 5. frida 通过 -H 参数指定设备地址
frida-ps -H 192.168.1.100
frida -H 192.168.1.100 -f com.example.app -l script.js

注意:无线连接要求 PC 和手机在同一局域网内。首次连接必须通过 USB 执行 adb tcpip 命令开启网络调试端口。

4. Frida 版本对应关系

Frida 环境搭建中最容易踩的坑就是版本不匹配frida-tools(PC 端)和 frida-server(设备端)的版本号必须严格一致,否则会出现各种诡异错误。

┌─────────────────────┐        RPC        ┌─────────────────────┐
│   PC 端              │  ◄──────────────►  │   Android 设备端      │
│                     │                    │                     │
│  frida-tools v16.x  │    协议必须匹配     │  frida-server v16.x │
│  frida (Python 绑定) │                    │  (原生可执行文件)      │
└─────────────────────┘                    └─────────────────────┘

检查和同步版本的步骤:

# 查看 PC 端 frida 版本
frida --version

# 查看 frida-server 版本(设备端)
adb shell /data/local/tmp/frida-server --version

# 如果版本不一致,重新下载对应版本的 frida-server

安装指定版本的 frida-tools

pip install frida-tools==12.3.0 frida==16.1.11

经验法则:每次更新 PC 端 frida-tools 后,务必同步更新设备端的 frida-server。建议将两个版本的检查作为日常调试前的例行步骤。

5. 常见环境问题排查

5.1 Root 权限不足

现象frida-ps -U 提示 Failed to spawn: unable to find processaccess denied

排查

# 确认 root 权限
adb shell su -c id
# 预期输出: uid=0(root) gid=0(root)

# 如果 su 不可用,说明设备未 root 或 root 方案有问题
# Magisk 设备检查:
adb shell magisk -v

5.2 SELinux 阻止

现象:frida-server 启动后立即退出,无报错信息。

排查

# 查看 SELinux 状态
adb shell getenforce
# 如果输出 Enforcing,临时关闭:
adb shell su -c setenforce 0

永久关闭(仅限测试设备):编辑 /sys/fs/selinux/enforce 或通过 Magisk 的 SELinux 模块处理。生产环境不建议永久关闭 SELinux。

5.3 端口冲突

现象frida-ps -U 提示 Failed to attach 或连接超时。

排查

# 检查 27042 端口是否被占用(Frida 默认端口)
adb shell netstat -tlnp | grep 27042

# 如果被占用,使用自定义端口启动 frida-server
su -c /data/local/tmp/frida-server -l 0.0.0.0:27043

# PC 端连接时指定端口
frida-ps -H 127.0.0.1:27043

5.4 版本不匹配

现象:PC 端报 Failed to spawn: invalid UUIDProtocol mismatch 等错误。

解决:严格按照第 4 节的方法同步两端版本。

5.5 一键排查脚本

将以下脚本保存为 frida-check.sh,用于快速排查环境问题:

#!/bin/bash
echo "=== Frida 环境检查 ==="

echo -n "[PC] frida-tools 版本: "
frida --version 2>/dev/null || echo "未安装"

echo -n "[设备] frida-server 版本: "
adb shell /data/local/tmp/frida-server --version 2>/dev/null || echo "未找到"

echo -n "[设备] Root 状态: "
adb shell su -c id 2>/dev/null || echo "无 root 权限"

echo -n "[设备] SELinux: "
adb shell getenforce 2>/dev/null

echo -n "[设备] CPU 架构: "
adb shell getprop ro.product.cpu.abi

echo "=== 检查完毕 ==="

6. PC 端工具安装

6.1 Python 绑定

frida-tools 安装时已自动包含 Python 绑定。你可以直接在 Python 脚本中使用:

import frida

# 列出 USB 设备上的进程
device = frida.get_usb_device()
processes = device.enumerate_processes()
for p in processes:
    print(f"PID: {p.pid}, Name: {p.name}")

6.2 Node.js 绑定

如果你需要在 Node.js 环境中使用 Frida:

npm install frida
const frida = require('frida');

async function main() {
    const device = await frida.getUsbDevice();
    const processes = await device.enumerateProcesses();
    processes.forEach(p => console.log(`PID: ${p.pid}, Name: ${p.name}`));
}

main().catch(console.error);

6.3 frida-tools CLI 工具集

frida-tools 提供了一组强大的命令行工具:

工具 用途
frida 交互式 REPL 和脚本注入
frida-ps 列出进程(类似 ps 命令)
frida-trace 跟踪函数调用
frida-discover 自动发现内部函数
frida-kill 终止进程
frida-ls-devices 列出可用设备

7. IDE 配置推荐

7.1 VSCode + Frida 插件

VSCode 是编写 Frida 脚本的首选 IDE,推荐安装以下插件:

  1. Frida — 提供 Frida JavaScript API 的智能补全和语法高亮
  2. Python — Microsoft 官方 Python 插件,用于编写 Python 端控制脚本
  3. Prettier — 格式化 JavaScript 脚本

VSCode 的 tasks.json 配置示例(一键注入脚本):

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Frida: 注入脚本",
            "type": "shell",
            "command": "frida",
            "args": ["-U", "-f", "com.example.app", "-l", "${file}"],
            "problemMatcher": []
        }
    ]
}

7.2 PyCharm 调试配置

当你使用 Python 编写 Frida 控制脚本时,可以在 PyCharm 中直接调试:

import frida
import sys

def on_message(message, data):
    if message['type'] == 'send':
        print(f"[*] {message['payload']}")
    elif message['type'] == 'error':
        print(f"[!] {message['description']}")

# 连接 USB 设备
device = frida.get_usb_device()

# 附加到目标进程
session = device.attach("目标进程名")

# 加载脚本
with open("hook.js", "r", encoding="utf-8") as f:
    script = session.create_script(f.read())

script.on("message", on_message)
script.load()

print("[*] 脚本已加载,按回车退出...")
sys.stdin.read()

在 PyCharm 中右键运行即可启动调试,支持断点调试 Python 逻辑。

8. 第一个 Frida 脚本

8.1 编写 Hook 脚本

创建 hook_android.js 文件:

// Hook android.widget.Toast 的 show 方法
Java.perform(function () {
    var Toast = Java.use("android.widget.Toast");

    // Hook show() 方法
    Toast.show.overload().implementation = function () {
        console.log("[*] Toast.show() 被调用!");
        // 打印调用栈
        console.log(Java.use("android.util.Log").getStackTraceString(
            Java.use("java.lang.Exception").$new()
        ));
        // 调用原始方法
        this.show();
    };

    console.log("[*] Toast Hook 已生效");
});

8.2 运行脚本

# -U: USB 连接
# -f: 以 Spawn 模式启动应用(推荐,可在应用启动前注入)
# -l: 加载脚本文件
frida -U -f com.example.app -l hook_android.js --no-pause

如果应用已在运行,可以使用 Attach 模式:

# -n: 通过进程名附加
frida -U -n com.example.app -l hook_android.js

# -p: 通过 PID 附加
frida -U -p 12345 -l hook_android.js

9. 常用命令行参数详解

frida 命令的核心参数:

参数 全称 说明
-U --usb 连接 USB 设备
-R --remote 连接远程 frida-server
-D --device 指定设备 ID
-H --host 指定远程主机地址
-f --file Spawn 模式:启动应用并注入
-n --name Attach 模式:通过进程名附加
-p --pid Attach 模式:通过 PID 附加
-l --load 加载 JavaScript 脚本
--no-pause Spawn 模式下自动恢复应用执行
-e --eval 直接执行一段 JavaScript 代码
-o --output 将输出重定向到文件

常用组合示例:

# Spawn 模式启动并注入(最常用)
frida -U -f com.target.app -l exploit.js --no-pause

# Attach 到正在运行的进程
frida -U -n "进程名" -l monitor.js

# 通过 IP 连接远程设备
frida -H 192.168.1.100:27042 -n "进程名" -l hook.js

# 直接执行单行代码
frida -U -f com.target.app -e "Java.perform(function(){ console.log('Hello Frida!'); })"

# 输出重定向到日志文件
frida -U -n "进程名" -l hook.js -o output.log

10. 实战案例:搭建完整环境并 Hook 系统 API

本节通过一个完整的案例,演示从环境搭建到成功 Hook 系统 API 的全过程。

10.1 目标分析

我们将 Hook android.os.Build 类的静态字段,在任意应用启动时读取并打印设备指纹信息。这个案例简单但实用,可以验证整个 Frida 环境是否正常工作。

10.2 编写脚本

创建 device_info.js

Java.perform(function () {
    var Build = Java.use("android.os.Build");

    console.log("\n========== 设备指纹信息 ==========");
    console.log(" Manufacturer : " + Build.MANUFACTURER.value);
    console.log(" Model        : " + Build.MODEL.value);
    console.log(" Brand        : " + Build.BRAND.value);
    console.log(" SDK_INT      : " + Build.VERSION.SDK_INT.value);
    console.log(" Release      : " + Build.VERSION.RELEASE.value);
    console.log(" Fingerprint  : " + Build.FINGERPRINT.value);
    console.log("====================================\n");

    // Hook getprop 流程 — 拦截 System.getProperty
    var System = Java.use("java.lang.System");
    System.getProperty.overload("java.lang.String").implementation = function (key) {
        var result = this.getProperty(key);
        console.log("[System.getProperty] " + key + " = " + result);
        return result;
    };
});

10.3 执行和验证

# 确认 frida-server 正在运行
adb shell "ps -A | grep frida-server"

# 如果未运行,启动它
adb shell "su -c /data/local/tmp/frida-server -D &"

# 等待 2 秒确保服务启动完成
sleep 2

# 列出设备进程确认连接正常
frida-ps -U | head -n 5

# Spawn 模式启动系统设置并注入
frida -U -f com.android.settings -l device_info.js --no-pause

预期输出:

[*] Spawned `com.android.settings`
========== 设备指纹信息 ==========
 Manufacturer : Google
 Model        : Pixel 6
 Brand        : google
 SDK_INT      : 33
 Release      : 13
 Fingerprint  : google/oriole/oriole:13/TQ3A.230901.001/...
====================================

[System.getProperty] ro.build.version.sdk = 33
[System.getProperty] ro.product.model = Pixel 6
[System.getProperty] ro.product.manufacturer = Google
...

10.4 环境验证清单

当你看到上述输出时,说明以下所有环节均已正常:

  • ✅ PC 端 frida-tools 已正确安装
  • frida-server 版本与 PC 端匹配
  • ✅ 设备已 root,frida-server 以 root 权限运行
  • ✅ USB 连接正常或无线连接稳定
  • ✅ JavaScript 注入引擎工作正常
  • ✅ Java 层 Hook 功能正常

11. 总结

Frida 环境搭建看似步骤繁多,但核心只有三个要点:

  1. 版本一致frida-toolsfrida-server 版本号必须完全匹配
  2. Root 权限:frida-server 必须以 root 身份运行
  3. 网络通畅:PC 和设备之间的通信端口(默认 27042)不能被占用或阻断

掌握本文的内容后,你就拥有了 Frida 逆向分析的基础能力。后续我们将深入学习 Frida 的 Java 层 Hook、Native 层 Hook、以及反检测等高级技巧。


参考链接